package top.lilele.adminSystem.utils;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.util.IdUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import top.lilele.adminSystem.dto.PageDto;
import top.lilele.adminSystem.entity.AdminFileEntity;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.beans.Introspector;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 工具类
 *
 * @author lilele
 */
@Slf4j
public class Utils {
    /**
     * 白名单
     */
    public static String[] authWhiteList = {"/user/login", "/user/generateCode", "/*.html", "/swagger-resources", "/webjars/**", "/**/api-docs","/favicon.ico"};

    /**
     * stream切断进行分页（主要处理连表查询，多次查询问题）
     *
     * @param list
     * @param pageNum
     * @param pageSize
     * @return
     */
    public static PageDto generatePage(List list, Integer pageNum, Integer pageSize) {
        PageDto page = new PageDto();
        Object collect = list.stream().skip((long) (pageNum - 1) * pageSize).limit(pageSize).collect(Collectors.toList());
        page.setPage(Long.valueOf(pageNum));
        page.setSize(Long.valueOf(pageSize));
        page.setTotal((long) list.size());
        page.setList((List<Object>) collect);
        return page;
    }

    /**
     * 构建树形节点配置
     *
     * @param key
     * @param parentKey
     * @param name
     * @return
     */
    public static TreeNodeConfig generateTreeNode(Object key, Object parentKey, Object name) {
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setIdKey(key.toString());
        treeNodeConfig.setParentIdKey(parentKey.toString());
        treeNodeConfig.setChildrenKey("children");
        treeNodeConfig.setNameKey(name.toString());
        return treeNodeConfig;
    }

    /**
     * 生成唯一id
     *
     * @return
     */
    public static String generateId() {
        String s = IdUtil.fastSimpleUUID();
        return s;
    }

    /**
     * 生成完整文件信息
     *
     * @param multipartFile 文件
     * @return
     */
    public static AdminFileEntity generateFileInfo(MultipartFile multipartFile, String bucketName) {
        // 文件名称
        String filename = IdUtil.fastSimpleUUID();
        log.info("minio fileName {}", filename);
        // 构造文件实体
        AdminFileEntity adminFileEntity = new AdminFileEntity();
        adminFileEntity.setFileName(filename);
        adminFileEntity.setFileSize(multipartFile.getSize());
        adminFileEntity.setFileOriginName(multipartFile.getOriginalFilename());
        adminFileEntity.setBucketName(bucketName);
        adminFileEntity.setContentType(multipartFile.getContentType());
        // 获取文件后缀名（按照.来切割，除了第一个. 全部都是后缀名）
        String[] split = multipartFile.getOriginalFilename().split("\\.");
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 1; i < split.length; i++) {
            stringBuilder.append(".");
            stringBuilder.append(split[i]);
        }
        adminFileEntity.setFileExtension(stringBuilder.toString());
        return adminFileEntity;
    }

    @SneakyThrows
    public static <T> String getName(SerializableFunction<T, ?> fn) {
        // 获取序列化writeReplace方法
        Method method = fn.getClass().getDeclaredMethod("writeReplace");
        // 获取private字段
        boolean isAccessible = method.isAccessible();
        method.setAccessible(Boolean.TRUE);
        // 转化为lambda序列化
        SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
        method.setAccessible(isAccessible);
        // 从lambda信息取出method、field、class等
        String getterMethod = serializedLambda.getImplMethodName();
        String fieldName = Introspector.decapitalize(getterMethod.replace("get", ""));
        return fieldName;
    }

    /**
     * 公用导出excel
     *
     * @param list                待导出列表
     * @param fileName            文件名
     * @param mergeName           合并首行名
     * @param map                 字段集合
     * @param httpServletResponse 响应
     */
    @SneakyThrows
    public static void exportExcel(List list, String fileName, String mergeName, LinkedHashMap map, HttpServletResponse httpServletResponse) {
        ExcelWriter writer = ExcelUtil.getWriter();
        writer.merge(map.size() - 1, mergeName);
        map.forEach((key, value) -> {
            log.info("key {} value {}", key, value);
            writer.addHeaderAlias(key.toString(), value.toString());
        });
        writer.setOnlyAlias(true);
        writer.write(list, true);
        httpServletResponse.setCharacterEncoding("utf-8");
        httpServletResponse.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8"));
        ServletOutputStream out = httpServletResponse.getOutputStream();
        writer.flush(out, true);
        writer.close();
        IoUtil.close(out);
    }

    /**
     * byte转换成字符串
     *
     * @param byteNumber
     * @return
     */
    public static String formatByte(long byteNumber) {
        //换算单位
        double FORMAT = 1024.0;
        double kbNumber = byteNumber / FORMAT;
        if (kbNumber < FORMAT) {
            return new DecimalFormat("#.##KB").format(kbNumber);
        }
        double mbNumber = kbNumber / FORMAT;
        if (mbNumber < FORMAT) {
            return new DecimalFormat("#.##MB").format(mbNumber);
        }
        double gbNumber = mbNumber / FORMAT;
        if (gbNumber < FORMAT) {
            return new DecimalFormat("#.##GB").format(gbNumber);
        }
        double tbNumber = gbNumber / FORMAT;
        return new DecimalFormat("#.##TB").format(tbNumber);
    }

    /**
     * byte转换成mb
     *
     * @param byteNumber
     * @return
     */
    public static Long convertByteToMb(long byteNumber) {
        double FORMAT = 1024.0;
        double result = Double.parseDouble(String.format("%.2f", byteNumber / FORMAT / FORMAT));
        return (long) result;
    }
}
